package com.cube.share.formatter.letter;

import com.cube.share.formatter.annotation.LetterSensitive;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.format.Formatter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.Locale;

/**
 * @author cube.li
 * @date 2021/4/4 22:33
 * @description 字母格式化器
 */
@Slf4j
public class LetterFormatter implements Formatter<String> {

    private LetterSensitive.Position position;

    private LetterSensitive.Type type;

    private Integer length;

    private Boolean lenient;

    public LetterFormatter(@NonNull LetterSensitive.Position position,
                           @NonNull LetterSensitive.Type type,
                           @NonNull Integer length,
                           @NonNull Boolean lenient) {
        this.position = position;
        this.type = type;
        this.length = length;
        this.lenient = lenient;
    }

    private String convert(@Nullable String content) {
        if (StringUtils.isBlank(content)) {
            return content;
        }
        if (position == LetterSensitive.Position.ALL) {
            return convertByType(content, type);
        }
        ConvertRegion region = getConvertRegion(content);
        return letterConvert(content, region.getStart(), region.getEnd(), type);
    }

    private ConvertRegion getConvertRegion(String content) {
        int start = 0, end = length;
        if (!lenient && length > content.length()) {
            throw new StringIndexOutOfBoundsException("please check the length");
        }
        if (end > content.length()) {
            end = content.length();
        }
        switch (position) {
            case LEFT:
                break;
            case RIGHT:
                start = content.length() - length;
                break;
            default:
                throw new UnsupportedOperationException("position type must be LEFT or RIGHT!");
        }
        return new ConvertRegion(start, end);
    }


    /**
     * 对指定位置区间进行大小写转换,[start,end)
     *
     * @param raw   原字符串
     * @param start 起始位置 包含
     * @param end   结束位置 不包含
     * @param type  转换类型
     * @return 转换后
     */
    private String letterConvert(@NonNull String raw, int start, int end, LetterSensitive.Type type) {
        int length = raw.length();
        String remainStr1 = raw.substring(0, start),
                convertStr = raw.substring(start, end),
                remainStr2 = raw.substring(end, length);
        convertStr = convertByType(convertStr, type);
        return remainStr1 + convertStr + remainStr2;
    }

    private String convertByType(@NonNull String content, @NonNull LetterSensitive.Type type) {
        switch (type) {
            case TO_LOWER:
                content = content.toLowerCase();
                break;
            case TO_UPPER:
                content = content.toUpperCase();
                break;
            default:
                break;
        }
        return content;
    }

    @Override
    public String parse(String text, Locale locale) {
        log.info("LetterSensitive 生效...");
        return convert(text);
    }

    @Override
    public String print(String object, Locale locale) {
        log.info("LetterSensitive 生效...");
        return convert(object);
    }

    /**
     * 替换区间
     */
    @AllArgsConstructor
    @Getter
    private static class ConvertRegion {

        Integer start;

        Integer end;
    }

}
